package com.um.springboot.starter.interceptors;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.um.springboot.starter.annotation.ApiPermission;
import com.um.springboot.starter.code.CommonCode;
import com.um.springboot.starter.constants.Constants;
import com.um.springboot.starter.core.StringJsonRedisTemplate;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.helper.SessionHelper;
import com.um.springboot.starter.properties.HshProperties;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Created by renjunwei on 2020/9/17
 */
@Slf4j
@Aspect
@Component
@Order(value = AspectOrders.API_PERMISSION)
@ConditionalOnProperty(value = "hsh.api-permission.enabled", matchIfMissing = true)
public class ApiPermissionInterceptor {

    @Autowired
    private HshProperties hshProperties;

    @Autowired
    private StringJsonRedisTemplate redisTemplate;

    @Autowired
    private SessionHelper sessionHelper;

    //@Around注解 环绕执行，就是在调用之前和调用之后，都会执行一定的逻辑
    @Around("execution(* com.um..controller.*.*(..)) || execution(* com.hsh..controller.*.*(..))")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

        //获取方法注解
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        ApiPermission method = signature.getMethod().getAnnotation(ApiPermission.class);
        ApiPermission clazz = pjp.getTarget().getClass().getAnnotation(ApiPermission.class);

        //获取类注解
        if (method != null && clazz != null && StrUtil.isAllNotBlank(method.value(), clazz.value())) {
            String permission = StrUtil.format("{}{}{}", clazz.value(), hshProperties.getApiPermission().getConcatStr(), method.value());
            log.debug("[{}] check permission: {}", hshProperties.getConfig().getSessionType(), permission);

            if ("sa-token".equals(hshProperties.getConfig().getSessionType())) {
                StpUtil.checkPermission(permission);
            } else {
                String userId = sessionHelper.getSessionUserId();
                if (StrUtil.isBlank(userId)) {
                    throw new ServiceException(CommonCode.LoginExpired);
                }
                List<String> permList = (List<String>) redisTemplate.opsForValue().get(Constants.API_PERMISSION + ":" + userId);
                String classAllPerm = StrUtil.format("{}{}*", clazz.value(), hshProperties.getApiPermission().getConcatStr());
                if (CollUtil.isEmpty(permList) || !CollUtil.containsAny(permList, CollUtil.toList("*", classAllPerm, permList))) {
                    throw new ServiceException(CommonCode.NoApiPermission);
                }
            }
        }

        return pjp.proceed();
    }

}
